package com.xwx.common.model;
import java.util.List;
import java.util.UUID;
import org.apache.log4j.Logger;

import com.jfinal.aop.Before;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.Table;
import com.jfinal.plugin.activerecord.TableMapping;
import com.jfinal.plugin.activerecord.tx.Tx;
import com.xwx.common.utils.DateUtils;
import com.xwx.common.utils.TypeConversionUtils;
import com.xwx.common.utils.MySqlAutoBuiderClassUtils;
import com.xwx.common.utils.Condition;

/**
 * @Description:model扩展，所有model都建议继承此model
 * 提供基于UUID主键模式
 * 提供软删除，需有字段isDel支持
 * 提供常用的方法
 * @author:Dream QQ:68697015
 * @time:2015年8月6日 下午4:01:02
 */
@SuppressWarnings({ "serial", "rawtypes" })
@Before(Tx.class)
public class ModelExt<M extends Model> extends Model<M>{
	/**
	 * 
	 * 全局日志
	 */
	protected Logger log=Logger.getLogger(getClass());
	
	/**
	 * 是否启用插入验证
	 */
	protected boolean isValidata=true;
	
	/**
	 * 主键
	 */
	protected String pkName;
	/**
	 * 表名
	 */
	protected Table table;
	
	/**
	 * 是否设置UUID主键
	 * 默认为true
	 */	
	protected boolean IS_UUID_PrimaryKey=true;
	/**
	 * 软删除字段名称
	 * 如果数据库表中有该字段，则实现软删除
	 */	
	protected String IS_DEL="del";
	/**
	 * 创建日期
	 */	
	protected String CREATE_DATE="createDate";
	/**
	 * 创建人
	 */	
	protected String CREATE_USER="createUserId";
	/**
	 * 更新日期
	 */	
	protected String UPDATE_DATE="updateDate";
	/**
	 * 更新人
	 */	
	protected String UPDATE_USER="updateUserId";
	/**
	 * 启用状态，0启用，1禁用
	 */	
	protected String STATUS="status";
	/**
	 * 排序号，默认100
	 */	
	protected String SORT="sort";
	/**
	 * 上级节点编号
	 */	
	protected String PID="pId";
	
	public ModelExt(){
		table=TableMapping.me().getTable(getClass());
		pkName=table.getPrimaryKey()[0];
	}
	/**
	 * 主键自动生成UUID
	 */
	public boolean save(){
		//主键
		if(IS_UUID_PrimaryKey){
			this.set(pkName, UUID.randomUUID().toString());
		}
		//设置通用字段
		if (checkFieldExist(CREATE_DATE) && TypeConversionUtils.isEmpty(get(CREATE_DATE))) { //创建时间
			this.set(CREATE_DATE, DateUtils.getCurrentTime());
		}
		if (checkFieldExist(STATUS) && TypeConversionUtils.isEmpty(get(STATUS))) {
			this.set(STATUS, 0);
		}
		if (checkFieldExist(SORT) && TypeConversionUtils.isEmpty(getStr(SORT))) {
			this.set(SORT, 100);
		}
		if (checkFieldExist(IS_DEL)) {
			this.set(IS_DEL, 0);
		}
		//增加字段默认值设置以非空验证
		//if(isValidata)validata();
		//如果不是UUID，移除主键，让数据库设值
		if(!IS_UUID_PrimaryKey)remove(pkName);
		return super.save();
	}
	public void validata(){
		log.info("验证/设置数据库字段");
		List<Record> list = MySqlAutoBuiderClassUtils.getColumnsByTableName(table.getName());
		for (Record record : list) {
			String colName=record.getStr("COLUMN_NAME");
			//如果不是uuid主键，则不对主键进行验证，因为有可能由数据库设值
			if(!IS_UUID_PrimaryKey && colName.equals(pkName))continue;
			if(StrKit.notBlank(record.getStr("COLUMN_DEFAULT")))set(colName,record.getStr("COLUMN_DEFAULT"));
			log.info("验证是否为NULL"+get(colName).toString());
			if(record.getStr("IS_NULLABLE").equals("NO") && StrKit.isBlank(get(colName).toString()))throw new NullPointerException(colName+"("+record.getStr("COLUMN_COMMENT")+"),不允许为NULL值");
		}
	}
	/**
	 * 更新
	 * @return true成功
	 */
	public boolean update(){
		if (table.hasColumnLabel(UPDATE_DATE) && TypeConversionUtils.isEmpty(get(UPDATE_DATE))) {
			this.set(UPDATE_DATE, DateUtils.getCurrentTime());
		}
		//if(isValidata)validata();
		return super.update();
	}
	/**
	 * 删除单条数据
	 * 支持软删除
	 * @return true成功
	 */
	public boolean deleteById(Object idValue){
		M _model=queryById(idValue);
		if(_model==null)throw new NullPointerException("主键："+idValue+" 数据不存在，或已删除");
		if(checkChildExist(_model.get(pkName).toString())){
			throw new RuntimeException("主键："+idValue+"存在子节点数据，请先删除子节点数据");
		}
		if(checkFieldExist(IS_DEL)){
			queryById(idValue).set(IS_DEL, 1).update();
			return true;
		}
		return super.deleteById(idValue);
	}
	/**
	 * 删除多条数据
	 * 支持软删除
	 * @return true成功
	 */
	public boolean deleteById(Object...idValues){
		boolean b =true;
		for (Object object : idValues) {
			deleteById(object);
		}
		return b;
	}
	/**
	 * 根据条件批量删除数据
	 * @param condition 条件，可用sqlutils进行拼接
	 * @return true 成功
	 */
	public boolean deleteByCondition(String condition){
		boolean b =true;
		List<M> list=queryListByCondition(condition);
		for (M m : list) {
			deleteById(m.get(pkName));
		}
		return b;
	}
	/**
	 * 根据主键查找单条数据
	 * @return model
	 */
	public M queryById(Object obj){
		return queryByCondition(new Condition().eq(pkName, obj).toString());
	}
	/**
	 * 根据条件查询单条信息
	 * @param Condition 可使用SQLUtils拼接
	 * @return model
	 */
	public M queryByCondition(String condition){
		//如有删除字段就只取正常数据
		String defaultCondition=checkFieldExist(IS_DEL)?" and "+IS_DEL+"=0 or "+IS_DEL+" is null":"";
		if(StrKit.isBlank(condition))defaultCondition="where 1=1 "+defaultCondition;
		return findFirst("select * from "+table.getName()+condition+defaultCondition);
	}	
	/**
	 * 查询当前model所有数据,如有软删除标识，将只取未删除的数据
	 * 如果有sort字段，则按sort降序，如果没有则按主键降序
	 * @return list
	 */
	public List<M> queryList(){
		return queryListByCondition(null,null,null);
	}
	/**
	 * 根据条件查询数据,如有软删除标识，将只取未删除的数据
	 * @param Condition 条件　建议使用SQLUtils进行组合条件
	 * @return list
	 */
	public List<M> queryListByCondition(String condition){
		return queryListByCondition(null,condition,null);
	}
	/**
	 * 根据条件查询数据,如有软删除标识，将只取未删除的数据
	 * @param field 要显示的字段，如name,id,username as lastName等
	 * @param Condition 条件　建议使用SQLUtils进行组合条件
	 * @return list
	 */
	public List<M> queryListByCondition(String field,String condition){
		return queryListByCondition(field,condition,null);
	}	
	/**
	 * 根据条件查询列表数据,如有软删除标识，将只取未删除的数据
	 * @param field　要显示的字段
	 * @param condition　条件 可使用sqlUtils进行拼接
	 * @param order　排序，例如：order by id desc,默认排序方式为：如果有sort字段，就按该字段，没有则按主键
	 * @return list
	 */
	public List<M> queryListByCondition(String field,String condition,String order){
		String _filed="*";
		String _condition="";
		String _order=getSort();
		//如有删除字段就只取正常数据
		String defaultCondition=checkFieldExist(IS_DEL)?" and "+IS_DEL+"=0 or "+IS_DEL+" is null":"";
		if(StrKit.notBlank(field))_filed=field;
		if(StrKit.notBlank(condition))_condition=condition;
		if(StrKit.isBlank(condition))defaultCondition="where 1=1 "+defaultCondition;
		if(StrKit.notBlank(order))_order=" "+order;
		return find("select "+_filed+" from "+table.getName()+_condition+defaultCondition+_order);
	}
	/**
	 * 根据父级节点ID查询子节点数据，如果有pId字段
	 * @param idValue 父级节点ID
	 * @return list
	 */
	public List<M> queryChildList(Object idValue){
		if(table.hasColumnLabel(PID)){
			return queryListByCondition(new Condition().eq(PID, idValue).toString());
		}
		throw new NullPointerException("无父子关联标识："+PID+",无法获取子级数据");
	}
	/**
	 * 通用分页
	 * @param field 要显示的字段
	 * @param condition 条件
	 * @param order 排序
	 * @param pageNumber 当前页
	 * @param pageSize 每页条数
	 * @return
	 */
	public Page<M> queryPage(String field,String condition,String order,int pageNumber,int pageSize){
		String _select="select *";
		String _condition="";
		String _order=getSort();
		//如有删除字段就只取正常数据
		String defaultCondition=checkFieldExist(IS_DEL)?" and "+IS_DEL+"=0 or "+IS_DEL+" is null":"";
		if(StrKit.notBlank(field))_select="select "+field;
		if(StrKit.notBlank(condition))_condition=condition;
		if(StrKit.isBlank(condition))defaultCondition=" where 1=1 "+defaultCondition;
		if(StrKit.notBlank(order))_order=" "+order;
		return paginate(pageNumber, pageSize, _select, "from "+table.getName()+_condition+defaultCondition+_order);
	}

	/**
	 * 获取默认排序方式，如果有sort字段，就以该字段排序，如果没有，就按主键
	 * 默认排序为降序
	 * @return order by xxx xxx
	 */
	public String getSort(){
		String sortName=pkName;
		String order="desc";
		if(table.hasColumnLabel(SORT))sortName=SORT;
		return " order by "+sortName+" "+order;
	}
	/**
	 * 启用（如果有status属性）
	 * @return true成功 0启用
	 */
	public boolean enable(){
		return updateStatus(0);
	}
	/**
	 * 禁用（如果有status属性）1禁用
	 * @return true成功
	 */
	public boolean disable(){
		return updateStatus(1);
	}
	/**
	 * 设置状态
	 * @param flag　0启用,1禁用
	 * @return true成功
	 */
	private boolean updateStatus(int flag){
		boolean b = false;
		if(table.hasColumnLabel(STATUS)){
			b=this.set(STATUS,flag).update();
		}
		return b;
	}
	/**
	 * 更新排序号
	 * @param sort
	 * @return true 成功
	 */
	public boolean updateSort(int sort){
		boolean b = false;
		if(table.hasColumnLabel(SORT)){
			b=this.set(SORT,sort).update();
		}
		return b;		
	}
	/**
	 * 检测某字段是否存在
	 * @param field
	 * @return true存在
	 */
	public boolean checkFieldExist(String field){
		return table.hasColumnLabel(field)?true:false;
	}
	/**
	 * 检测是否有子节点，通过pId检测
	 * @param id 要检测的节点主键
	 * @return true 有子节点
	 */
	public boolean checkChildExist(String idValue){
		boolean b = false;
		if(checkFieldExist(PID)){
			if(queryByCondition(new Condition().eq(PID, idValue).toString())!=null)b=true;	
		}
		return b;
	}	
}
